/*
 * This program (in conjunction to send) illustrates the basic
 * scenario in which the receiver inserts a public trigger and
 * the sender sends packets to the receiver's id.
 * Usage:
 * > recv_public_trigger <cfg_file.xml>
 * > send_public_id  <cfg_file.xml> <id>
 * (id is printed out by recv_public_trigger)
 */ 


#include <stdio.h>

#include "i3.h"
#include "i3_client_api.h"
#include "utils.h"

/* callbacks */
void receive_payload(cl_trigger *t, void *data, void *fun_ctx)
{
  long seq;

  cl_buf *clb = (cl_buf *) data;
  if (clb->data_len) {
    seq = ntohl(*((long *)(clb->data)));
    printf("recv. seq. #: %ld \n", seq);
  }
}

void constraint_failed(cl_trigger *t, void *data, void* fun_ctx)
{
  printf("Trigger constraint failed\n");
}

void trigger_inserted(cl_trigger *t, void *data, void* fun_ctx)
{
  printf("Trigger inserted\n");
}

void trigger_failure(cl_trigger *t, void *data, void* fun_ctx)
{
  printf("Trigger failed\n");

  /* reinsert trigger */
  if (cl_insert_trigger(t, 0) != CL_RET_OK ) {
    printf ("error while inserted trigger\n");
  }
}

int i3_main_loop(char *cfg_file)
{
  ID id;
  cl_trigger *t;
  int rc;
  Key key;

  /* create and initialize the context */
  if (cl_init(cfg_file) != CL_RET_OK) {
    printf("Error creating context!\n");
    exit(-1);
  }

  /* chose a random ID and key */
  set_random_id(&id);
  set_random_key(&key);

  /* 
   * Create and insert a trigger of form (id, R).
   * Make the trigger left constrained; left constrained
   * triggers are resistant to eavesdropping and impersonation attacks,
   * since an attacker cannot insert a trigger with the same ID unless
   * it knows the key
   * NOTE: The key field of id will be updated, i.e., id.key = h_l(key) 
   */
  t = cl_create_trigger(&id, ID_LEN_BITS, &key, 
			CL_TRIGGER_CFLAG_L_CONSTRAINT|CL_TRIGGER_CFLAG_PUBLIC);
  /* print trigger's ID */
  printf("trigger's ID: "); print_id(&id);

  /* insert trigger */
  if (cl_insert_trigger(t, 0) != CL_RET_OK) {
    printf ("error while inserted trigger\n");
  }

  /* associate callbacks with the inserted trigger */
  cl_register_trigger_callback(t, CL_CBK_TRIGGER_CONSTRAINT_FAILED, 
			       constraint_failed, NULL);
  cl_register_trigger_callback(t, CL_CBK_RECEIVE_PAYLOAD, 
			       receive_payload, NULL);
  cl_register_trigger_callback(t, CL_CBK_TRIGGER_INSERTED, 
			       trigger_inserted, NULL);
  cl_register_trigger_callback(t, CL_CBK_TRIGGER_REFRESH_FAILED, 
			       trigger_failure, NULL);

  /* loop and call cl_select */
  cl_loop();

  /* remove & destroy trigger */
  cl_remove_trigger(t);
  cl_destroy_trigger(t);

  /* destroy context */
  cl_exit();
}


int main(int argc, char **argv)
{

  if (argc != 2) {
    printf("%s <cfg_file.xml>\n", argv[0]);
    exit(-1);
  }
  
  i3_main_loop(argv[1]);
  return -1;
}

